#include "constantvisitor.h"
#include "attrnames.h"
#include "../semantics/visitordata.h"

void ConstantVisitor::postVisitClass()
{
	if (data()->Classes->shouldPrintTables())
	{
		printf("Current class: %s\n",data()->CurrentClass->cnode()->name().c_str());
		data()->CurrentClass->constantTable()->print();
		printf("\n");
	}
}
void ConstantVisitor::visitClass()
{
 data()->CurrentClass->initConstantTable();
 ClassSemantic * sem=data()->CurrentClass;
 ConstantTable * table=sem->constantTable();
 ClassCode & attrs=sem->codedClass();
 
 attrs.MyName=table->createClass(sem->cnode()->name());

 if (sem->isInterface())
 {
	 attrs.SuperClass=table->createClass("java/lang/Object");
	 for (unsigned int i=0;i<sem->semanticInheritCount();i++)
	 {
		 std::string curUsed=sem->semanticInherit(i);
		  attrs.Interfaces.push_back(table->createClass(curUsed));
	 }
	 attrs.HasConstructor=false;
 }
 else
 {
	 std::string superClassName;
	 for (unsigned int i=0;i<sem->semanticInheritCount();i++)
	 {
		 std::string curUsed=sem->semanticInherit(i);
		 ClassSemantic * sem=data()->Classes->getClassByName(curUsed);
		 if (sem->isInterface())
			 attrs.Interfaces.push_back(table->createClass(curUsed));
		 else
			 superClassName=curUsed;
	 }
	 attrs.SuperClass=table->createClass(superClassName);
	 attrs.HasConstructor=true;
	 attrs.MyConstructor=table->createConstructor();
	 attrs.ParentConstructor=table->createConstructorRef(superClassName);
	 attrs.Code=CREATE_CODE(table);
 }
 attrs.HasMain=data()->CurrentClass->isRoot();
 if (attrs.HasMain)
 {
	 Method * newMethod=data()->CurrentClass->getRootMethod();
	 attrs.MainProc=table->createMainDefinition();
	 attrs.RootConstructorMethodRef=table->createConstructorRef(sem->cnode()->name());

	 std::string name,methodname,descriptor;
	 newMethod->getRefInfo(name,methodname,descriptor);
	 attrs.RootProcMethodRef=table->createMethodRef(name,methodname,descriptor);
	 if (newMethod->hasSpecificArguments())
			attrs.Convert=table->createMainConvertToArray();
	 else
			attrs.Convert=INVALID_CONVERT;
	 attrs.PopBeforeExit=newMethod->returnType()!=NULL;
	 attrs.Code=CREATE_CODE(table);
 }
}
void ConstantVisitor::visitMethod()
{
    ClassSemantic * sem=data()->CurrentClass;
    ConstantTable * table=sem->constantTable();
	Method * curmeth=data()->CurrentMethod;
	const Method * ovnonabs=curmeth->getOverridenNonAbstractMethod();
	MethodCode & attrs=curmeth->codeAttrs();
	
	attrs.Code=CREATE_CODE(table);
	std::string commondescriptor;
	if (ovnonabs)
	 {
		std::string name;
		const_cast<Method*>(ovnonabs)->getCommonCompilableSignature(name,commondescriptor);
		attrs.CompilingMethod=table->createDefinition(name,commondescriptor);
		attrs.CompilingMethodRef=table->createMethodRef(sem->cnode()->name(),name,commondescriptor);
		curmeth->getCommonCompilableSignature(name,commondescriptor);
		attrs.ReferencingMethods.push_back(table->createDefinition(name,commondescriptor));

		for (unsigned int i=0;i<curmeth->m_overriden_methods.size();i++)
		 {
			 Method * overriden=&(curmeth->m_overriden_methods[i]);
			 if (overriden!=ovnonabs)
			 {
			    overriden->getCommonCompilableSignature(name,commondescriptor);
				attrs.ReferencingMethods.push_back(table->createDefinition(name,commondescriptor));
			 }
		 }
	 }
	 else
	 {
		 std::string name;
		 curmeth->getCommonCompilableSignature(name,commondescriptor);
		 attrs.CompilingMethod=table->createDefinition(name,commondescriptor);
		 attrs.CompilingMethodRef=table->createMethodRef(sem->cnode()->name(),name,commondescriptor);

		 for (unsigned int i=0;i<curmeth->m_overriden_methods.size();i++)
		 {
			 Method * overriden=&(curmeth->m_overriden_methods[i]);
			 overriden->getCommonCompilableSignature(name,commondescriptor);
			 attrs.ReferencingMethods.push_back(table->createDefinition(name,commondescriptor));
		 }

	 }
	//Create signature if needed
	std::string name;
	std::string sig;
	
	curmeth->getFullCompilableSignature(name,sig);
	if (sig!=commondescriptor)
	{
		attrs.Signature=CREATE_SIGNATURE(table);
		attrs.SignatureDescriptor=table->createUTF8(sig);
	}
	else attrs.Signature=INVALID_CONSTANT;

	attrs.HasResult=curmeth->returnType()!=NULL;
	if (attrs.HasResult)
	{
		attrs.ResultIndex=(unsigned char)(curmeth->getResultVariableIndex());
	}

	attrs.FormalArgumentCount=curmeth->totalFormalArgs();
	attrs.TotalLocalArguments=curmeth->totalLocalVarsCount();

	//Here we just visit a current method, attributing every node
	if (curmeth->routine() && curmeth->shouldCompileMainMethod())
		curmeth->routine()->fillConstant(data());
}

void ConstantVisitor::visitField()
{
	FieldCode & attrs=data()->CurrentField->code();

	std::string name;
	std::string descriptor;
	std::string fulldescriptor;
	data()->CurrentField->getCommonCompilableSignature(name,descriptor);
	data()->CurrentField->getFullCompilableSignature(name,fulldescriptor);
	attrs.FieldInfo=data()->currentTable()->createDefinition(name,descriptor);
	if (descriptor!=fulldescriptor)
	{
		attrs.Signature=CREATE_SIGNATURE(data()->currentTable());
		attrs.SignatureInfo=data()->currentTable()->createUTF8(fulldescriptor);
	}
	else
	{
		attrs.Signature=INVALID_CONSTANT;
	}

}